﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Celeriq.Common;

namespace Celeriq.RepositoryAPI
{
	internal class QueryDimensionTheader
	{
		private DataQueryResults _newResults = null;
		private IEnumerable<DataItemExtension> _queriedList = null;
		private List<DimensionItem> _dimensionList = null;
		private RepositoryDefinition _definition = null;
		private int _dimensionIndex = 0;
		private object _locker = new object();

		public QueryDimensionTheader(DataQueryResults newResults, IEnumerable<DataItemExtension> queriedList, List<DimensionItem> dimensionList, RepositoryDefinition definition, int dimensionIndex)
		{
			_newResults = newResults;
			_queriedList = queriedList;
			_dimensionList = dimensionList;
			_definition = definition;
			_dimensionIndex = dimensionIndex;
		}

		public void ProcessDimension()
		{
			try
			{
				var dimension = _dimensionList[_dimensionIndex];
				var dimensionDef = _definition.DimensionList.First(x => x.Name == dimension.Name);
				var rIDList = dimension.RefinementList.Select(x => x.DVIdx);
				if (_newResults.Query.DimensionValueList != null)
				{
					if (_newResults.Query.DimensionValueList.Any(x => rIDList.Contains(x))) return;
				}

				var d1 = new DimensionItem() {Name = dimension.Name, DIdx = dimension.DIdx, NumericBreak = dimension.NumericBreak};

				#region Lists

				if (dimensionDef.DataType == RepositoryDefinition.DataTypeConstants.List)
				{
					foreach (var item in _queriedList)
					{
						var dvidxBase = ((d1.DIdx - DimensionDefinition.DGROUP) + 1)*DimensionDefinition.DVALUEGROUP;
						foreach (var dvidx in item.DimensionValueArray.Where(x => dvidxBase <= x && x < (dvidxBase + DimensionDefinition.DVALUEGROUP)))
						{
							var rItem = d1.RefinementList.FirstOrDefault(x => x.DVIdx == dvidx);
							if (rItem == null)
							{
								rItem = ((ICloneable) dimension.RefinementList.First(x => x.DVIdx == dvidx)).Clone() as RefinementItem;
								rItem.Count = 1;
								d1.RefinementList.Add(rItem);
							}
							else
							{
								rItem.Count++;
							}

						}
					}
				}
				#endregion

				#region Strings, Dates, Numbers (with no bands)

				else if (d1.NumericBreak == null)
				{
					var r1 = (from x in _queriedList
					          where x.DimensionSingularValueArray[_dimensionIndex] != null
					          group x by x.DimensionSingularValueArray[_dimensionIndex]
					          into g
					          select new {Key = g.Key, Count = g.Count()}).ToList();

					foreach (var r in r1)
					{
						var refinement = new RefinementItem();
						refinement.DVIdx = r.Key.Value;
						refinement.FieldValue = dimension.RefinementList.First(x => x.DVIdx == r.Key).FieldValue;
						refinement.Count = r.Count;
						if ((dimensionDef.DataType == RepositoryDefinition.DataTypeConstants.Float) || (dimensionDef.DataType == RepositoryDefinition.DataTypeConstants.Int))
						{
							refinement.MinValue = long.Parse(refinement.FieldValue);
							refinement.MaxValue = refinement.MinValue;
						}
						d1.RefinementList.Add(refinement);
					}
				}
				#endregion

				#region Ints with bands

				else //with numeric bands
				{
					var r1 = (from x in _queriedList
					          where x.DimensionSingularValueArray[_dimensionIndex] != null
					          group x by x.DimensionSingularValueArray[_dimensionIndex]
					          into g
					          select new {Key = g.Key, Count = g.Count()}).ToList();

					foreach (var r in r1)
					{
						var rItem = dimension.RefinementList.FirstOrDefault(x => x.DVIdx == r.Key);
						if (rItem != null)
						{
							var refinement = new RefinementItem();
							refinement.DVIdx = r.Key.Value;
							refinement.FieldValue = rItem.FieldValue;
							refinement.Count = r.Count;
							refinement.MinValue = rItem.MinValue;
							refinement.MaxValue = rItem.MaxValue;
							d1.RefinementList.Add(refinement);
						}
					}
				}

				#endregion

				//Do not add dimensions with [0..1] items
				//if (d1.RefinementList.Count > 1)
					_newResults.DimensionList.Add(d1);

			}
			catch (Exception ex)
			{
				throw;
			}
		}

	}
}